#include <buola/gui.h>

#include <buola/gui/cwindow.h>

#include <buola/gui/x11/cx11drop.h>
#include <buola/gui/dnd/cdrop.h>
#include <buola/gui/dnd/cdroptarget.h>

namespace buola { namespace gui { namespace x11 {

using namespace x11;

CX11Drop::CX11Drop(CDrop *pDrop)
{
    mDrop=pDrop;
    mAcceptedAction=DND_NONE;
}

//////////
// drop
//

void CX11Drop::DropSendStatus(Window,bool /*pAccept*/,bool /*pEvents*/,const CRect_d&)
{
    ///\todo
//    Window lS=mMessageWindow->GetID();
//    Atom lAction=0;
//    int lFlags=0;
//
//    if(pAccept) //check requested action and compare with accepted actions
//    {
//        int lRequested=AtomToAction(mRequestedAction);
//        if(lRequested&mDrop->mAcceptedActions)
//        {
//            lAction=mRequestedAction;
//            mAcceptedAction=(EDNDActions)mRequestedAction;
//        }
//        else if(mDrop->mAcceptedActions&DND_COPY)
//        {
//            lAction=get_default_x11_display()->Atoms().mDndActionCopy;
//            mAcceptedAction=DND_COPY;
//        }
//        else if(mDrop->mAcceptedActions&DND_SPECIAL)
//        {
//            lAction=get_default_x11_display()->Atoms().mDndActionPrivate;
//            mAcceptedAction=DND_SPECIAL;
//        }
//        else
//        {
//            pAccept=false;
//            mAcceptedAction=DND_NONE;
//        }
//    }
//    else
//        mAcceptedAction=DND_NONE;
//
//    if(pAccept) lFlags|=0x01;
//    if(pEvents) lFlags|=0x02;
//
//    get_default_x11_display()->SendClientMessage(pW,pW,get_default_x11_display()->Atoms().mDndStatus,lS,lFlags,
//            (((int)pArea.l)<<16)|((int)pArea.t),
//            (((int)(pArea.r-pArea.l))<<16)|(((int)(pArea.b-pArea.t))),
//            lAction);
}

///////////////
// callbacks
//

void CX11Drop::ProcessDndEnter(XClientMessageEvent *pE)
{
    mAvailableTargets.clear();

    if(pE->data.l[1]&0x01) //more types supported
    {
        get_default_x11_display()->GetWindowProperty(pE->data.l[0],get_default_x11_display()->Atoms().mDndTypeList,
                        mAvailableTargets);
    }
    else
    {
        for(int i=2;i<=4;i++)
        {
            if(pE->data.l[i])
                mAvailableTargets.push_back((Atom)pE->data.l[i]);
        }
    }
}

void CX11Drop::ProcessDndPosition(XClientMessageEvent *pE)
{
    CPoint_d lPoint(pE->data.l[2]>>16,pE->data.l[2]&0xffff);
    CWindow *lW=mMessageWindow->FindChildAtRoot(lPoint);
    CDropTarget *lTarget=CDropTarget::GetTarget(lW);

    //Translate coordinates to target window
    lPoint=lW->TranslateCoords(lPoint,nullptr);
    mRequestedAction=pE->data.l[4];

    if(lTarget!=mDrop->Target())
    {
        //Finish with previous target (if it exists)
        if(mDrop->Target())
        {
            mDrop->Target()->OnDropLeave(mDrop,mLastPoint);
        }

        //Start with new target
        mDrop->SetDropTarget(lTarget);

        if(mDrop->Target())
        {
            mDrop->Target()->OnDropEnter(mDrop,lPoint);
        }
    }

    mLastPoint=lPoint;

    if(!mDrop->Target())
    {
        //TODO:must get position, and create a function in CWindow to get
        //absolute position
        DropSendStatus(pE->data.l[0],false,false,CRect_d(0,0,0,0));
    }
    else
    {
        mDrop->Target()->OnDropMove(mDrop,lPoint);

        DropSendStatus(pE->data.l[0],mDrop->Accepted(),false,CRect_d(0,0,0,0));
    }
}

void CX11Drop::ProcessDndLeave(XClientMessageEvent*)
{
    if(mDrop->Target())
    {
        mDrop->Target()->OnDropLeave(mDrop,mLastPoint);
        mDrop->SetDropTarget(nullptr);
    }
}

void CX11Drop::ProcessDndDrop(XClientMessageEvent *pE)
{
    if(!mAcceptedAction)
    {
        msg_warn() << "Received drop after not accepting\n";
        return;
    }

    if(mDrop->Target())
    {
        mTimestamp=pE->data.l[2];
        mDrop->Target()->OnDropDrop(mDrop,mLastPoint,mAcceptedAction);
    }
}

EDNDActions CX11Drop::AtomToAction(Atom pAtom)
{
    if(pAtom==get_default_x11_display()->Atoms().mDndActionCopy)
        return DND_COPY;
    else if(pAtom==get_default_x11_display()->Atoms().mDndActionMove)
        return DND_MOVE;
    else if(pAtom==get_default_x11_display()->Atoms().mDndActionLink)
        return DND_LINK;
    else if(pAtom==get_default_x11_display()->Atoms().mDndActionAsk)
        return DND_ASK;
    else if(pAtom==get_default_x11_display()->Atoms().mDndActionPrivate)
        return DND_SPECIAL;
    else
        throw XArgument(I18N("Wrong DND action\n"));
}

/*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }
